package org.uim.cricket.updater.impl;

import java.io.File;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

import org.uim.cricket.db.impl.ExistMatch;
import org.uim.cricket.updater.Ulogger;
import org.uim.cricket.updater.Updatable;
import org.uim.cricket.updater.UpdaterProperties;
import org.uim.cricket.updater.entities.CricketMatchNew;
import org.uim.cricket.updater.fetch.Fetchable;
import org.uim.cricket.updater.fetch.URLGeneratable;
import org.uim.cricket.updater.parser.CricketMatchIDParsable;
import org.uim.cricket.updater.parser.MatchListParsable;
import org.uim.cricket.updater.parser.SingleMatchParsable;
import org.uim.cricket.util.io.FileSaver;

public class CricInfoWebUpdater implements Updatable {

	private Fetchable fetcher = null;
	private URLGeneratable yearMatchURLGenerator = null;
	private URLGeneratable singleMatchURLGenerator = null;
	private MatchListParsable matchListParser = null;
	private SingleMatchParsable singleMatchParser = null;
	private CricketMatchIDParsable matchIDParser = null;
	
	// Sri lanka
	private Map<String, String> teams = null; 	
	private Map<String, String> matchTypes = null;
	
	@Override
	public boolean update(Calendar startDate, UpdaterProperties prop) throws Exception {
		
		Ulogger.printSubHeader(" Starting CricInfo Web Updater...");
		if (teams == null) {
			Ulogger.error(" No team is found for updating...");
			Ulogger.error("  ** Updating FAILED!");
			return false;
		}
		if (this.matchTypes == null) {
			Ulogger.error(" No match types are defined for updating...");
			Ulogger.error("  ** Updating FAILED!");
			return false;
		}
		
		int year = startDate.get(Calendar.YEAR);
		Calendar today = Calendar.getInstance();
		int todayYear = today.get(Calendar.YEAR);
		int errs = 0;
		
		String[] args = new String[3];
		for (String team : this.teams.keySet()) {
			
			args[2] = teams.get(team);
			
			for (String mType : this.matchTypes.keySet()) {
				
				args[0] = this.matchTypes.get(mType);
				
				for (int y=year;y<=todayYear;y++) {
					
					args[1] = y + "";
					
					Ulogger.debug(" --------------------------------------------------------");
					Ulogger.debug(" Started looking for:");
					Ulogger.debug("      Team:       " + team);
					Ulogger.debug("      Match Type: " + mType);
					Ulogger.debug("      Year:       " + y);
					Ulogger.debug(" --------------------------------------------------------");
					
					String url = this.yearMatchURLGenerator.generateURL(args);
					
					Ulogger.debug(" Fetching URL: " + url);
					
					StringBuffer html = null;
					try {
						html = this.fetcher.fetch(url);
						
						String tmpFile = prop.getProperty("temp.dir");
						if (tmpFile != null) {
							File folder = new File(tmpFile);
							if (!folder.exists()) folder.mkdir();
							if (!tmpFile.endsWith("/")) tmpFile += "/";
							tmpFile += ("MatchList " + mType + "-" + year + "-" + team + ".html");
							FileSaver fs = new FileSaver(tmpFile);
							fs.write(html);
						}
						
					} catch (Exception ex) {
						errs++;
						Ulogger.error(" Failed to fetch from source!!!", ex);
						continue;
					}
					
					List<CricketMatchNew> nmatches = null;
					try {
						
						nmatches = this.matchListParser.parseNewMatches(html);
						if (nmatches == null || nmatches.size() == 0) {
							Ulogger.debug(" No new matches are found!");
							continue;
						}
						
						Ulogger.debug(" #"+ nmatches.size()+" new matches found.");
						
					} catch (Exception ex) {
						Ulogger.debug(" Failed to fetch from source!!!", ex);
						errs++;
						continue;
					}
					
					
					boolean makeGroups = (prop.getProperty("group.by.matchtype").equalsIgnoreCase("yes") ? true : false);
					
					try {
						
						for (int i=0;i<nmatches.size();i++) {
							CricketMatchNew aMatch = nmatches.get(i);
							String[] ids = this.matchIDParser.parseMatchID(aMatch.getMatchId());
							
							if (ids == null) {
								Ulogger.error("Match ID is unable to parse! Skipping. ['"+aMatch.getMatchId()+"']"); 
								continue;
							}
							
							String destFolder = prop.getProperty("dest.fetched.dir");
							String repoDestFolder = prop.getProperty("match.repository.dir");
							if (!destFolder.endsWith("/")) destFolder += "/";
							if (!repoDestFolder.endsWith("/")) repoDestFolder += "/";
							
							String mID = aMatch.getMatchId();
							if (mID == null || mID.length() == 0) continue;
							mID = mID.replaceAll(" ", "");
							ExistMatch ematch = new ExistMatch(mID);
							if (ematch.exists()) {
								Ulogger.debug(" Match is already in the database. ['" + mID + "']");
								Ulogger.debug("  Skipped.");
								continue;
							}
							if (new File(repoDestFolder + ids[0] + "/" + aMatch.getMatchId() + ".html").exists()) {
								Ulogger.debug(" Match is already in the repository dir. ['" + aMatch.getMatchId() + "']"); 
								Ulogger.debug("  Skipped.");
								continue;
							}
							
							Ulogger.debug(" Loading match: [" + aMatch.getMatchId() + ": " + aMatch.getTeam1() + " v " + aMatch.getTeam2() + " at " + aMatch.getGround() + ", " + aMatch.getDate() + "]");
							
							String mUrl = this.singleMatchURLGenerator.generateURL(
												new String[] {aMatch.getMatchURL()});
							
							Ulogger.debug("   Fetching match [" + mUrl + "]...");
							
							StringBuffer src = this.fetcher.fetch(mUrl);
							Ulogger.debug("   Successfully fetched.");
							
							Ulogger.debug("   Separating proper match score card...");
							StringBuffer theMatch = this.singleMatchParser.parseSingleMatch(src);
							Ulogger.debug("   ok.");
							
							String filename = destFolder;
							if (makeGroups) {
								if (this.matchIDParser != null) {
									filename += ids[0] + "/";
									repoDestFolder += ids[0] + "/";
								} else {
									Ulogger.warn("   No match type grouping is done, because CricketMatchIDParsable interface is empty!");
								}
							}
							
							File df = new File(filename);
							if (!df.exists()) df.mkdir();
							
							filename += aMatch.getMatchId() + ".html";
							repoDestFolder += aMatch.getMatchId() + ".html";
							Ulogger.debug("   Saving match to file [" + filename + "]...");
							FileSaver fs = new FileSaver(filename);
							fs.write(theMatch);
							
							File repoMatchHTML = new File(repoDestFolder);
							if (!repoMatchHTML.exists()) {
								Ulogger.debug("     - Saving to '" + repoDestFolder + "'...");
								fs = new FileSaver(repoDestFolder);
								fs.write(theMatch);
								Ulogger.debug("     ok");
							}
							Ulogger.debug("   ok.");		
							
						}
						
					} catch (Exception ex) {
						errs++;
						Ulogger.debug("  Error occured fetching match!", ex);
					}
					
				}
				
			}
			
		}
		
		String td = today.get(Calendar.YEAR) + "/" + (today.get(Calendar.MONTH)+1) + "/" + today.get(Calendar.DATE);
		prop.setProperty("last.updated.date", td);
		prop.write();
		
		if (errs > 0) {
			Ulogger.printSubHeader(" Some ERRORS ocuured when updating. Please check for log.");
			return false;
		} else {
			Ulogger.printSubHeader(" Successfully Completed CricInfo Web updater!");
			return true;
		}
	}

	public void setYearMatchURLGenerator(URLGeneratable yearMatchURLGenerator) {
		this.yearMatchURLGenerator = yearMatchURLGenerator;
	}
	
	public void setSingleMatchURLGenerator(
			URLGeneratable singleMatchURLGenerator) {
		this.singleMatchURLGenerator = singleMatchURLGenerator;
	}
	
	public void setFetcher(Fetchable fetcher) {
		this.fetcher = fetcher;
	}
	
	public URLGeneratable getYearMatchURLGenerator() {
		return yearMatchURLGenerator;
	}
	
	public URLGeneratable getSingleMatchURLGenerator() {
		return singleMatchURLGenerator;
	}
	
	public Fetchable getFetcher() {
		return fetcher;
	}
	
	public void setSingleMatchParser(SingleMatchParsable singleMatchParser) {
		this.singleMatchParser = singleMatchParser;
	}
	
	public void setMatchListParser(MatchListParsable matchListParser) {
		this.matchListParser = matchListParser;
	}
	
	public SingleMatchParsable getSingleMatchParser() {
		return singleMatchParser;
	}
	
	public MatchListParsable getMatchListParser() {
		return matchListParser;
	}
	
	public void setTeams(Map<String, String> teams) {
		this.teams = teams;
	}
	
	public void setMatchTypes(Map<String, String> matchTypes) {
		this.matchTypes = matchTypes;
	}
	
	public Map<String, String> getTeams() {
		return teams;
	}
	
	public Map<String, String> getMatchTypes() {
		return matchTypes;
	}
	
	public void setMatchIDParser(CricketMatchIDParsable matchIDParser) {
		this.matchIDParser = matchIDParser;
	}
	
	public CricketMatchIDParsable getMatchIDParser() {
		return matchIDParser;
	}
}
